package com.msh.starter.common.web.api;


import com.msh.frame.client.common.Result;
import com.msh.frame.client.interfaces.IClassLoadLog;
import com.msh.frame.interfaces.ICodeDescEnum;
import com.msh.frame.interfaces.ICodeEnum;
import com.msh.frame.interfaces.IValueDescEnum;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.PostConstruct;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.reflections.Reflections;
import org.reflections.scanners.SubTypesScanner;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@Tag(name = "编码描述枚举-api相关接口")
@RestController
@RequestMapping("/api/enum")
@ConditionalOnProperty(name = "msh.starter.web.api.value-desc.enable", havingValue = "true", matchIfMissing = true)
public class EnumApi implements IClassLoadLog {


  private final static Map<String, List<ValueDescVO>> valueDescMap = new HashMap<>();
  private final static Map<String, List<CodeDescVO>> codeDescMap = new HashMap<>();
  private final static Map<String, List<CodeVO>> codeMap = new HashMap<>();
  @Value("${msh.starter.web.api.value-desc.packagePrefix:com.msh}")
  private String packagePrefix;

  @Override
  public String logInfo() {
    return new StringBuilder()
        .append("----执行类 ")
        .append(EnumApi.class)
        .append("\r\n")
        .append("--------加载类 ")
        .append(EnumApi.class)
        .append("\r\n")
        .append("------------参数 ")
        .append("msh.starter.web.api.value-desc.packagePrefix: ")
        .append(packagePrefix)
        .append("\r\n")
        .toString();
  }

  @PostConstruct
  public void postConstruct()
      throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
    initEnum(packagePrefix);
  }

  @Operation(summary = "获取枚举信息")
  @GetMapping("valueDesc/get")
  public Result<List<ValueDescVO>> getValueDesc(@RequestParam("enum") String parm) {
    List<ValueDescVO> valueDescVOList = valueDescMap.get(parm);
    if (CollectionUtils.isEmpty(valueDescVOList)) {
      return Result.successReturn(Collections.emptyList());
    }
    return Result.successReturn(valueDescVOList);
  }

  @Operation(summary = "获取枚举列表")
  @GetMapping("valueDesc/list")
  public Result<Map<String, List<ValueDescVO>>> listValueDesc(@RequestParam("enums") String[] enums) {
    Map<String, List<ValueDescVO>> resultMap = new HashMap<>();
    for (String parm : enums) {
      List<ValueDescVO> valueDescVOList = valueDescMap.get(parm);
      if (CollectionUtils.isEmpty(valueDescVOList)) {
        resultMap.put(parm, Collections.emptyList());
      }
      resultMap.put(parm, valueDescVOList);
    }
    return Result.successReturn(resultMap);
  }

  @Operation(summary = "获取枚举信息")
  @GetMapping("codeDesc/get")
  public Result<List<CodeDescVO>> getCodeDesc(@RequestParam("enum") String parm) {
    List<CodeDescVO> codeDescVOList = codeDescMap.get(parm);
    if (CollectionUtils.isEmpty(codeDescVOList)) {
      return Result.successReturn(Collections.emptyList());
    }
    return Result.successReturn(codeDescVOList);
  }

  @Operation(summary = "获取枚举列表")
  @GetMapping("codeDesc/list")
  public Result<Map<String, List<CodeDescVO>>> listCodeDesc(@RequestParam("enums") String[] enums) {
    Map<String, List<CodeDescVO>> resultMap = new HashMap<>();
    for (String parm : enums) {
      List<CodeDescVO> codeDescVOList = codeDescMap.get(parm);
      if (CollectionUtils.isEmpty(codeDescVOList)) {
        resultMap.put(parm, Collections.emptyList());
      }
      resultMap.put(parm, codeDescVOList);
    }
    return Result.successReturn(resultMap);
  }

  @Operation(summary = "获取枚举信息")
  @GetMapping("code/get")
  public Result<List<CodeVO>> getCode(@RequestParam("enum") String parm) {
    List<CodeVO> valueDescVOList = codeMap.get(parm);
    if (CollectionUtils.isEmpty(valueDescVOList)) {
      return Result.successReturn(Collections.emptyList());
    }
    return Result.successReturn(valueDescVOList);
  }

  @Operation(summary = "获取枚举列表")
  @GetMapping("code/list")
  public Result<Map<String, List<CodeVO>>> listCode(@RequestParam("enums") String[] enums) {
    Map<String, List<CodeVO>> resultMap = new HashMap<>();
    for (String parm : enums) {
      List<CodeVO> valueDescVOList = codeMap.get(parm);
      if (CollectionUtils.isEmpty(valueDescVOList)) {
        resultMap.put(parm, Collections.emptyList());
      }
      resultMap.put(parm, valueDescVOList);
    }
    return Result.successReturn(resultMap);
  }


  public static void initEnum(String packagePrefix)
      throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
    Reflections reflections = new Reflections(packagePrefix, new SubTypesScanner(false));
    Set<Class<? extends IValueDescEnum>> valueDescEnumClass = reflections.getSubTypesOf(IValueDescEnum.class);
    if(CollectionUtils.isEmpty(valueDescEnumClass)){
      log.info("未获取IValueDescEnum枚举类信息");
    }else {
      log.info("开始加载IValueDescEnum枚举类:");
      for (Class c : valueDescEnumClass) {
        log.info("----------{}", c.getName());
        Method method = c.getMethod("values");
        IValueDescEnum[] valueDescEnums = (IValueDescEnum[]) method.invoke(null);
        valueDescMap.put(c.getSimpleName(),
            Arrays.asList(valueDescEnums).stream().map(cEnum -> new ValueDescVO(cEnum))
                .collect(Collectors.toList()));
      }
    }

    Set<Class<? extends ICodeDescEnum>> codeDescEnumClass = reflections.getSubTypesOf(ICodeDescEnum.class);
    if(CollectionUtils.isEmpty(codeDescEnumClass)){
      log.info("未获取ICodeDescEnum枚举类信息");
    }else {
      log.info("开始加载ICodeDescEnum枚举类:");
      for (Class c : codeDescEnumClass) {
        log.info("----------{}", c.getName());
        Method method = c.getMethod("values");
        ICodeDescEnum[] codeDescEnums = (ICodeDescEnum[]) method.invoke(null);
        codeDescMap.put(c.getSimpleName(),
            Arrays.asList(codeDescEnums).stream().map(cEnum -> new CodeDescVO(cEnum))
                .collect(Collectors.toList()));
      }
    }

    Set<Class<? extends ICodeEnum>> codeEnumClass = reflections.getSubTypesOf(ICodeEnum.class);
    if(CollectionUtils.isEmpty(codeEnumClass)){
      log.info("未获取ICodeEnum枚举类信息");
    }else {
      log.info("开始加载ICodeEnum枚举类:");
      for (Class c : codeEnumClass) {
        log.info("----------{}", c.getName());
        Method method = c.getMethod("values");
        ICodeEnum[] codeEnums = (ICodeEnum[]) method.invoke(null);
        codeMap.put(c.getSimpleName(),
            Arrays.asList(codeEnums).stream().map(cEnum -> new CodeVO(cEnum))
                .collect(Collectors.toList()));
      }
    }

  }




  @Data
  public static class ValueDescVO {
    private Integer value;
    private String desc;

    public ValueDescVO() {
    }

    public ValueDescVO(IValueDescEnum valueDescEnum) {
      this.value = valueDescEnum.getValue();
      this.desc = valueDescEnum.getDesc();
    }
  }

  @Data
  public static class CodeDescVO {
    private String code;
    private String desc;

    public CodeDescVO() {
    }

    public CodeDescVO(ICodeDescEnum codeDescEnum) {
      this.code = codeDescEnum.getCode();
      this.desc = codeDescEnum.getDesc();
    }
  }

  @Data
  public static class CodeVO {
    private String code;

    public CodeVO() {
    }

    public CodeVO(ICodeEnum codeEnum) {
      this.code = codeEnum.getCode();
    }
  }
}
